package leetcode.juc;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用原子类本地测试可以，但是不能通过，不知道为什么
 * CAS过不了，不知道咋回事
 */
//class FooBar {
//    private int n;
//
//    private volatile AtomicInteger num = new AtomicInteger(1);
//
//    public FooBar(int n) {
//        this.n = n;
//    }
//
//    public void foo(Runnable printFoo) throws InterruptedException {
//
//        for (int i = 0; i < n; i++) {
//            while (true) {
//                if (num.get() == 1) {
//                    break;
//                }
//            }
//
//            // printFoo.run() outputs "foo". Do not change or remove this line.
//            printFoo.run();
//            while (true) {
//                if (num.compareAndSet(1, 2)) {
//                    break;
//                } else {
//                    TimeUnit.MILLISECONDS.sleep(200);
//                }
//            }
//        }
//    }
//
//    public void bar(Runnable printBar) throws InterruptedException {
//
//        for (int i = 0; i < n; i++) {
//
//            while (true) {
//                if (num.get() == 2) {
//                    break;
//                }
//            }
//
//            // printBar.run() outputs "bar". Do not change or remove this line.
//            printBar.run();
//            while (true) {
//                if (num.compareAndSet(2, 1)) {
//                    break;
//                }else {
//                    TimeUnit.MILLISECONDS.sleep(200);
//                }
//            }
//        }
//    }
//}


class FooBar {
    private int n;

    public FooBar(int n) {
        this.n = n;
    }

    Semaphore foo = new Semaphore(1);
    Semaphore bar = new Semaphore(0);

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            foo.acquire();
            printFoo.run();
            bar.release();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            bar.acquire();
            printBar.run();
            foo.release();
        }
    }
}


public class leetcode1115 {
    public static void main(String[] args) {

        FooBar fooBar = new FooBar(5);

        new Thread(() -> {
            try {
                fooBar.foo(new Runnable() {
                    @Override
                    public void run() {
                        print("foo");
                    }
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "A").start();


        new Thread(() -> {
            try {
                fooBar.bar(new Runnable() {
                    @Override
                    public void run() {
                        print("bar");
                        try {
                            TimeUnit.MILLISECONDS.sleep(300);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "B").start();
    }

    private static void print(String s) {
        System.out.print(s);
    }
}
